#pragma once

#include <mmsystem.h>
#include <mmreg.h>
#include <dsound.h>
#include <afxmt.h>
/*!
 * \file 
 * DxSoundEx.h
 */

/*!
 * \brief class for playing sounds.
 *
 * class for playing sounds.
 * This class uses DirectSound8 and its API
 *
 * - header file: DxSoundEx.h
 * - lib: sound.lib
 * - DLL: sound.dll
 */

class AFX_EXT_CLASS CDxSoundEx
{
public:
	CDxSoundEx(void);
	virtual ~CDxSoundEx(void);

public:
	/*!
	 * Creates and initializes an object that supports the IDirectSound8 interface
	 * And sets the cooperative level as a normal level of the application for this sound device
	 * 
	 * @param hWnd Handle to the application window.
	 *
	 * @return If TRUE, It creates direct sound successfully. Otherwise FALSE
	 */
	BOOL CreateDxSound(HWND hWnd);
	/*!
	 * Release all resources of DirectSound8
	 */
	void DeleteDxSound();

	/*!
	 * Check the status of creating  a sound buffer object
	 */
	BOOL IsCreateDSBuffer();
	/*!
	 * Creates a sound buffer object to manage audio samples
	 *
	 * @param pWaveFormatEx Address of a WAVEFORMATEX structure that describes audio format
	 * @param nBuffSec time in seconds that is a factor to define sound buffer size
	 * @param nBuffGapMSec time in milliseconds that is a factor to trigger to play or stop.
	 * nBuffGapMSec is smaller than nbuffSec.
	 * 
	 * @remark Creates a sound buffer referenced by nBuffSec. And starts to play since the buffer stacks as long as nBuffGapMSec
	 */
	BOOL CreateDSBuffer(WAVEFORMATEX *pWaveFormatEx, int nBuffSec, int nBuffGapMSec);
	/*!
	 * Releases the sound buffer
	 */
	void DeleteDSBuffer();
	/*!
	 * Initialize the sound buffer
	 */
	void InitAudioBuffer();

	//void RefreshDxSound(WAVEFORMATEX *pWaveFormatEx);
	/*!
	 * Check the changes of audio format between the previous one and the current one
	 * 
	 * @param pWaveFormatEx Address of a WAVEFORMATEX structure that describes audio format
	 * @param nBuffSec time in seconds that is a factor to define sound buffer size
	 * @param nBuffGapMSec time in milliseconds that is a factor to trigger to play or stop.
	 * nBuffGapMSec is smaller than nbuffSec.
	 *
	 * @return Returns 0 when Audio formats are the same, otherwise returns -1.
	 */
	int CompareFormat(WAVEFORMATEX *pWaveFormatEx, int nBuffSec, int nBuffGapMSec);
	void PlayStart();
	/*!
	 * Stops playing sound.
	 */
	void PlayStop();
	void SetFadeIn(BOOL bUse) { m_bUseFadeIn = bUse; };

	/*!
	 * Copy audio data to the DirectSound buffer. When stacks a certain amount, starts playing.
	 *
	 * @param pBuffer Pointer to a buffer containing the audio data to play
	 * @param nSize Size of the buffer referenced by pBuffer
	 */
	BOOL SetAudioBuffer(BYTE *pBuffer, int nSize);

	/*!
	 * Compares between the sound buffer size which occupied with valid data and dwGapSize
	 * 
	 * @param dwGapSize size in bytes
	 *
	 * @return returns TRUE if the sound buffer size which occupied with valid data is larger than dwGapSize. 
	 * FALSE otherwise.
	 */
	BOOL CheckDxBuffer(DWORD dwGapSize);

	int CheckDxBuffer2();

	/*!
	 * Returns the status of being playing.
	 *
	 * @return TRUE if the sound is playing. Otherwise FALSE.
	 */
	BOOL IsPlaying() { return m_bPlay; };
	/*!
	 * Returns the size of the buffer size which is stacked by valid audio data.
	 *
	 * @return the size of the buffer size in bytes which is stacked by valid audio data.
	 */
	DWORD GetGap() { 
		CheckDxBuffer(m_nBufferGapSize/4);
		return m_dwGap; 
	};
	/*!
	 * Returns the size of the buffer size which is defined by nBuffGapMSec of the function CreateDxBuffer.
	 *
	 * @return the size of the buffer size in bytes which is defined by nBuffGapMSec of the function CreateDxBuffer.
	 */
	DWORD GetGapThreshold() { return m_nBufferGapSize; };

protected:
	static UINT _procAudio(LPVOID lpParam);
	void procAudio();

private:
	LPDIRECTSOUND8			m_pDS;
	LPDIRECTSOUNDBUFFER		m_pDSBuffer;
	LPDIRECTSOUNDNOTIFY		m_pDSNotify;

	WAVEFORMATEX			m_WaveFormatEx;
	CCriticalSection		m_csDSBuffer;

	DWORD m_nPosHead;
	DWORD m_nPosTail;

	DWORD m_dwGap;

	CCriticalSection m_csPosHead;

	BOOL m_bUseFadeIn;

	int m_nBufferSize;
	int m_nBufferGapSize;

	BOOL m_bPlay;
	BOOL m_bReady;

	//thread
	BOOL m_bStopped;
	BOOL m_bStopSignal;
	BOOL m_bThread;

};
